package com.bestcem.xm.ticket.util;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bestcem.xm.ticket.cache.client.CacheProjectClient;
import com.bestcem.xm.ticket.cache.dto.SurveyProjectDTO;
import com.bestcem.xm.ticket.constant.Constants;
import com.bestcem.xm.ticket.dao.TicketConfigDao;
import com.bestcem.xm.ticket.dao.TicketDao;
import com.bestcem.xm.ticket.entity.mongo.Record;
import com.bestcem.xm.ticket.entity.mongo.Ticket;
import com.bestcem.xm.ticket.entity.mongo.TicketConfig;
import com.bestcem.xm.ticket.entity.mongo.TicketRule;
import com.bestcem.xm.ticket.enums.*;
import com.bestcem.xm.ticket.grpc.client.TicketBaseDeliverGrpcService;
import com.bestcem.xm.ticket.grpc.client.TicketBaseUserGrpcService;
import com.bestcem.xm.ticket.grpc.client.TicketSurveyGrpcService;
import com.bestcem.xm.ticket.grpc.client.TicketUserGrpcService;
import com.bestcem.xm.ticket.grpc.client.dto.deliver.DeliverAgainRecordDTO;
import com.bestcem.xm.ticket.grpc.client.dto.survey.RespondentDTO;
import com.bestcem.xm.ticket.grpc.client.dto.user.GroupDTO;
import com.bestcem.xm.ticket.mq.send.biz.TicketMessageSendService;
import com.bestcem.xm.ticket.service.AlertRecordService;
import com.bestcem.xm.ticket.service.TicketRuleService;
import com.bestcem.xm.ticket.service.TicketService;
import com.bestcem.xm.ticket.service.dto.mq.FilterDTO;
import com.bestcem.xm.ticket.service.dto.mq.TicketConfigCheckDTO;
import com.bestcem.xm.ticket.service.dto.mq.TitleHandleResultDTO;
import com.bestcem.xm.ticket.service.dto.ticket.CreateTicketDTO;
import com.bestcem.xm.ticket.service.dto.ticket.rule.TicketRuleCondition;
import com.bestcem.xm.ticket.service.manager.fsm.TicketFsmManager;
import com.bestcem.xm.ticket.service.manager.record.param.TransferParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.Executor;

/**
 * 工单配置Util
 *
 * @author jy.zhao
 * @version 1.0
 * @date 2021/8/17 14:43
 **/
@Slf4j
@Component
public class TicketConfigUtil {

    @Resource
    private TicketUtil ticketUtil;

    @Resource
    private TicketConfigDao ticketConfigDao;

    @Resource
    private TicketDao ticketDao;

    //@Resource
    //private TicketBaseQdesGrpcService ticketBaseQdesGrpcService;

    @Resource
    private TicketBaseUserGrpcService ticketBaseUserGrpcService;

    @Resource
    private TicketUserGrpcService ticketUserGrpcService;

    @Resource
    private TicketSurveyGrpcService ticketSurveyGrpcService;

    @Resource
    private TicketBaseDeliverGrpcService ticketBaseDeliverGrpcService;

    @Resource
    private AlertRecordService alertRecordService;

    @Resource
    private TicketService ticketService;

    @Resource
    private TicketRuleService ticketRuleService;

    @Resource
    private TicketFsmManager ticketFsmManager;

    @Resource
    private CacheProjectClient cacheProjectClient;
    //@Resource
    //private TicketMqProductUtil ticketMqProductUtil;

    @Resource
    private TicketMessageSendService ticketMessageSendService;

    @Resource(name = "ticket_create_executor")
    private Executor ticketCreateExecutor;

    /**
     * 检查工单配置
     *
     * @param ticketConfigDTO 工单配置dto参数
     * @author jy.zhao
     * @date 2021/8/17 14:51
     **/
    //@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void validConfigAndCreateTicket(TicketConfigCheckDTO ticketConfigDTO) {
        if (log.isInfoEnabled()) {
            log.info("[Ticket] 检查工单配置 start");
        }
        if (Objects.isNull(ticketConfigDTO)) {
            log.error("[ticket]: 检查工单配置-ticketConfigDTO参数为空");
            return;
        }
        if (ticketConfigDTO.getIsCopyDemo() != null && ticketConfigDTO.getIsCopyDemo()) {
            if (log.isInfoEnabled()) {
                log.info("[Ticket] demo数据不处理");
            }
            return;
        }
        if (ticketConfigDTO.getIsCopy() != null && ticketConfigDTO.getIsCopy()) {
            if (log.isInfoEnabled()) {
                log.info("[Ticket] solution拷贝和sample拷贝数据不处理");
            }
            return;
        }
        // 1. 校验传递的必要参数
        if (!validTicketConfigCheckParam(ticketConfigDTO)) {
            return;
        }
        // 调用python查询问卷的信息 获取问卷项目。
        SurveyProjectDTO surveyProject = cacheProjectClient.getSurveyProject(ticketConfigDTO.getProjectId());
        if (Validator.isNull(surveyProject)) {
            log.error("[Ticket] 检查工单配置MQ-没有找到问卷Id{}对应的问卷信息", ticketConfigDTO.getProjectId());
            return;
        }
        if (log.isInfoEnabled()) {
            log.info("[Ticket] 检查工单配置MQ-工单配置信息surveyProject={}", surveyProject);
        }
        // 2. 查询组织、问卷对应的开启的工单配置信息
        String orgId = surveyProject.getCompanyId();
        List<TicketConfig> ticketConfigList = ticketConfigDao.listTicketConfig(orgId, ticketConfigDTO.getProjectId(), TicketConfigStateEnum.ENABLE.getIndex());
        if (log.isInfoEnabled()) {
            log.info("[Ticket] 检查工单配置MQ-工单配置信息。数量={}， 详情={}", ticketConfigList.size(), ticketConfigList);
        }
        // 如果没有工单配置，就停止检查
        if (CollUtil.isEmpty(ticketConfigList)) {
            return;
        }
        // 3. 获取groupId和Name
        Map<String, String> groupInfo = getGroupIdName(orgId, ticketConfigDTO.getGroupCode(), surveyProject.getGroupList());
        groupInfo.put("surveyCode", surveyProject.getCode());
        // 4 根据答卷编号获取答案
        RespondentDTO respondentDTO = ticketSurveyGrpcService.getRespondent(ticketConfigDTO.getSeq(), true, false, false, "", true, "", ticketConfigDTO.getProjectId());
        if (Validator.isNull(respondentDTO) || Validator.isEmpty(Objects.requireNonNull(respondentDTO).getAnswers())) {
            log.error("[Ticket] 检查工单条件，没有获取到seq={}对应的答卷", ticketConfigDTO.getSeq());
            return;
        }
        // 4. 循环工单配置信息,检查工单的条件
        for (TicketConfig ticketConfig : ticketConfigList) {
            if (Validator.isEmpty(ticketConfig.getTicketRuleId())) {
                continue;
            }
            // 4.1 根据工单规则id查询工单规则条件
            TicketRule.Condition ticketCondition = ticketRuleService.getTicketRuleCondition(ticketConfig.getTicketRuleId());
            if (log.isInfoEnabled()) {
                log.info("[Ticket] 检查工单配置MQ-答卷题号：{}，工单配置id：{},工单规则id：{}", ticketConfigDTO.getSeq(), ticketConfig.getId(), ticketConfig.getTicketRuleId());
            }
            // 4.3 检查工单条件,根据结果判断需不需要生成工单
            Map<String, Object> checkResult = checkTicketConditionAndRule(respondentDTO, ticketCondition, ticketConfig.getId());
            if (log.isInfoEnabled()) {
                log.info("[Ticket] 检查工单配置MQ-工单规则条件结果：{}", checkResult);
            }
            // 4.4 校验通过
            if (Validator.isNotNull(checkResult) && toBool(checkResult.get("ret"))) {
                if (log.isInfoEnabled()) {
                    log.info("[Ticket] 检查工单配置MQ-检查工单条件成立：ticketConfigId {}", ticketConfig.getId());
                }
                // 4.4 保存告警记录
                Record alertRecord = new Record();
                alertRecord.setQProjectId(respondentDTO.getProjectId());
                alertRecord.setRuleList(Collections.singletonList(ticketCondition));
                alertRecord.setRspdSeq(ticketConfigDTO.getSeq());
                alertRecord.setData((JSONObject) JSON.toJSON(checkResult.get("data")));
                String recordId = alertRecordService.saveRecordInfo(alertRecord);

                // 4.5 创建工单记录
                CreateTicketDTO createTicketDTO = new CreateTicketDTO();
                createTicketDTO.setOrgId(orgId);
                // 设置为系统创建
                createTicketDTO.setOperationType(1);
                createTicketDTO.setSurveyTitle(surveyProject.getTitle());
                createTicketDTO.setSurveyId(ticketConfigDTO.getProjectId());
                createTicketDTO.setResId(ticketConfigDTO.getSeq());
                createTicketDTO.setMemberId(respondentDTO.getMemberId());
                createTicketDTO.setRegionName(groupInfo.getOrDefault("groupName", "全国"));
                createTicketDTO.setRegionId(groupInfo.get("groupId"));
                createTicketDTO.setTicketConfigId(ticketConfig.getId());
                createTicketDTO.setTicketConfig(ticketConfig);
                createTicketDTO.setAlertRecordId(recordId);
                createTicketDTO.setCreatedName("系统");
                createTicketDTO.setAlertRuleIdList(Collections.singletonList(ticketConfig.getId()));
                // 设置 工单满足的触发条件的名称
                LinkedList<String> triggerNames = new LinkedList<>();
                if (checkResult.containsKey(Constants.TRIGGER_NAMES) && checkResult.get(Constants.TRIGGER_NAMES) instanceof List) {
                    List list = (List) checkResult.get(Constants.TRIGGER_NAMES);
                    for (Object o : list) {
                        Optional<String> optionName = Optional.of(o).map(String::valueOf).map(String::trim).filter(StrUtil::isNotEmpty);
                        if (optionName.isPresent()) {
                            String triggerName = optionName.get();
                            if (!ObjectUtils.isEmpty(triggerName)) {
                                if (triggerName.length() > 15) {
                                    triggerName = triggerName.substring(0, 15);
                                }
                                triggerNames.add(triggerName);
                            }
                        }
                    }
                }
                createTicketDTO.setTriggerNames(triggerNames);
                // 在这里取消打印工单id日志，因为createTicket方法不会百分百创建工单
                Ticket ticket = null;
                try {
                    ticket = ticketUtil.createTicket(createTicketDTO);
                    // 发送工单创建mq消息
                    ticketMessageSendService.publishTicketCreateMQ(ticket, groupInfo);
                    TicketFsmRunnable ticketFsmRunnable = new TicketFsmRunnable(ticket, TicketEventEnum.SYSTEM_CREATED, new TransferParam(), ticketFsmManager);
                    // 工单状态流转
                    ticketCreateExecutor.execute(ticketFsmRunnable);
                } catch (Exception e) {
                    log.error("工单创建失败", e);
                }
                if (Validator.isNull(ticket)) {
                    break;
                }
                if (log.isInfoEnabled()) {
                    log.info("工单创建成功。ticket={}", ticket);
                }
            }
        }
        if (log.isInfoEnabled()) {
            log.info("[Ticket] 检查工单配置 finish");
        }
    }

    /**
     * 根据二次投放提交的答卷数据检查工单状态是否需要变更
     *
     * @param ticketConfigDTO 工单配置dto参数
     * @author jy.zhao
     * @date 2021/8/24 15:58
     **/
    public void validTicketConfigAndDeliver(TicketConfigCheckDTO ticketConfigDTO) {
        if (log.isInfoEnabled()) {
            log.info("[Ticket] 检查工单配置状态 start");
        }
        if (ticketConfigDTO.getIsCopyDemo()) {
            if (log.isInfoEnabled()) {
                log.info("[Ticket] demo数据不处理");
            }
            return;
        }
        // 1.校验必传参数规则
        if (!validTicketConfigCheckParam(ticketConfigDTO)) {
            return;
        }
        String againDeliverRecordId = ticketConfigDTO.getAgainDeliverRecordId();
        if (Validator.isEmpty(againDeliverRecordId)) {
            if (log.isInfoEnabled()) {
                log.info("[Ticket] 二次投放记录id为空，停止检查：{}", ticketConfigDTO);
            }
            return;
        }
        // 获取二次投放记录
        DeliverAgainRecordDTO deliverAgainRecordDTO = ticketBaseDeliverGrpcService.getAgainDeliverRecord(againDeliverRecordId);
        if (Validator.isNull(deliverAgainRecordDTO)) {
            log.error("[Ticket] 没有找到againDeliverRecordId={}对应的二次投放记录", againDeliverRecordId);
            return;
        }
        // 获取工单记录
        Objects.requireNonNull(deliverAgainRecordDTO);
        Ticket ticket = ticketDao.findById(deliverAgainRecordDTO.getTicketId());
        if (Validator.isNull(ticket)) {
            log.error("[Ticket] 没有找到ticketId={}对应的工单", deliverAgainRecordDTO.getTicketId());
            return;
        }
        // 工单配置
        TicketConfig ticketConfig = ticketConfigDao.findById(ticket.getTicketConfigId());
        if (Validator.isNull(deliverAgainRecordDTO)) {
            log.error("[Ticket] 没有找到ticketConfigId={}对应的工单配置", ticket.getTicketConfigId());
            return;
        }
        List<JSONObject> statusRuleList = ticketConfig.getStatusRuleList();
        if (CollUtil.isEmpty(statusRuleList)) {
            return;
        }
        if (log.isInfoEnabled()) {
            log.info("[Ticket] 检查工单配置状态 工单id={}, 工单配置id={}", ticket.getId(), ticketConfig.getId());
        }
        // 规则id=61436201414d0d030c00a471, 操作=1
        for (JSONObject statusRule : statusRuleList) {
            statusRule.getInnerMap().forEach((ruleId, operator) -> {
                TicketRule.Condition ticketCondition = ticketRuleService.getTicketRuleCondition(ruleId);
                boolean validCondition = validTicketCondition(ticketConfigDTO.getSeq(), ticketCondition, ticketConfigDTO.getProjectId());
                if (log.isInfoEnabled()) {
                    log.info("[Ticket] 检查工单配置状态MQ-规则id={}, seq={}, 操作={}", ruleId, ticketConfigDTO.getSeq(), operator);
                    log.info("[Ticket] 检查工单配置状态MQ-工单规则条件结果：{}", validCondition);
                }
                if (validCondition) {
                    String operate = Validator.isNotEmpty(operator) ? operator.toString() : Constants.UNSPECIFIED_TICKET_OPERATE;
                    ticketService.handleTicket(operate, ticket);
                }
            });
        }
        if (log.isInfoEnabled()) {
            log.info("[Ticket] 检查工单配置状态 finish");
        }
    }

    /**
     * 校验检查工单配置的必要参数
     *
     * @param ticketConfigDTO 工单配置参数
     * @return boolean
     * @author jy.zhao
     * @date 2021/8/24 17:27
     **/
    private static boolean validTicketConfigCheckParam(TicketConfigCheckDTO ticketConfigDTO) {
        if (Validator.isNull(ticketConfigDTO.getStatus())) {
            log.error("[Ticket] 参数校验未通过。没有传递答卷状态，停止检查：{}", ticketConfigDTO);
            return false;
        }
        // 如果是测试数据，停止检查
        if (Validator.isNotNull(ticketConfigDTO.getDataStatus()) && ticketConfigDTO.getDataStatus() != DataStatusEnum.FORMAL.getIndex()) {
            if (log.isInfoEnabled()) {
                log.info("[Ticket] 参数校验未通过。非正式数据,停止检查：{}", ticketConfigDTO);
            }
            return false;
        }
        // 答卷状态不是已完成或备用，停止检查
        if (ticketConfigDTO.getStatus() != RespondentStatusEnum.FINISH.getIndex() &&
                ticketConfigDTO.getStatus() != RespondentStatusEnum.BACKUP.getIndex()) {
            if (log.isInfoEnabled()) {
                log.info("[Ticket] 参数校验未通过。答卷状态不是已完成或备用，停止检查：{}", ticketConfigDTO);
            }
            return false;
        }
        if (Validator.isEmpty(ticketConfigDTO.getProjectId())) {
            if (log.isInfoEnabled()) {
                log.info("[Ticket] 参数校验未通过。没有传递项目id，停止检查：{}", ticketConfigDTO);
            }
            return false;
        }
        if (log.isInfoEnabled()) {
            log.info("[Ticket] 检查工单配置-参数校验通过：{}", ticketConfigDTO);
        }
        return true;
    }

    /**
     * 检查工单条件
     *
     * @param respondentDTO  答卷序号
     * @param condition      工单条件
     * @param ticketConfigId 工单配置id
     * @return Map<String, Object>
     * @author jy.zhao
     * @date 2021/8/17 17:43
     **/
    public Map<String, Object> checkTicketConditionAndRule(RespondentDTO respondentDTO, TicketRule.Condition condition, String ticketConfigId) {
        if (Validator.isNull(respondentDTO) || Validator.isNull(condition)) {
            return null;
        }
        HashMap<String, Object> result = new HashMap<>(2);
        List<Object> checkResult;
        try {
            Map<String, Object> conditionMap = BeanUtil.beanToMap(condition);
            JSONObject answer = SurveyAnswerValidUtil.toJSONObject(respondentDTO.getAnswers());
            Assert.notNull(answer, "checkTicketConditionAndRule answer is null");
            checkResult = parseTicketCondition(conditionMap, answer.getInnerMap(), RespondentStatusEnum.FINISH.getIndex());
            if (log.isInfoEnabled()) {
                log.info("[Ticket] 检查工单条件结果: {}", JSON.toJSON(checkResult));
            }
        } catch (Exception e) {
            log.error("[Ticket] 检查工单条件出错。工单配置id：{} ，答卷序号：{}, 工单触发条件{}, 问卷答案：{}", ticketConfigId, respondentDTO.getSeq(), condition, respondentDTO.getAnswers());
            return null;
        }
        Map<String, List<Object>> data = dealCheckTicketData(checkResult.get(1), ticketConfigId);
        result.put("ret", checkResult.get(0));
        result.put("data", data);
        if (checkResult.size() > 2) {
            result.put(Constants.TRIGGER_NAMES, checkResult.get(2));
        } else {
            result.put(Constants.TRIGGER_NAMES, new ArrayList<String>());
        }
        return result;
    }

    /**
     * 工单条件校验
     *
     * @param seq       答卷序号
     * @param condition 条件
     * @return boolean
     * @author jy.zhao
     * @date 2021/9/2 18:14
     **/
    public boolean validTicketCondition(Long seq, TicketRule.Condition condition, String projectId) {
        if (Validator.isEmpty(seq) || Validator.isNull(condition)) {
            return false;
        }
        RespondentDTO respondentBySeq = ticketSurveyGrpcService.getRespondent(seq, true, false, false, "", true, "", projectId);
        Objects.requireNonNull(respondentBySeq);
        if (Validator.isNull(respondentBySeq) || Validator.isEmpty(respondentBySeq.getAnswers())) {
            log.error("[Ticket] 检查工单条件，没有获取到seq={}对应的答卷", seq);
            return false;
        }
        try {
            Map<String, Object> conditionMap = BeanUtil.beanToMap(condition);
            JSONObject answer = SurveyAnswerValidUtil.toJSONObject(respondentBySeq.getAnswers());
            if (log.isInfoEnabled()) {
                log.info("[Ticket] 检查工单条件. 答卷序号：{}, 工单触发条件{}, 问卷答案：{}", seq, condition, respondentBySeq.getAnswers());
            }
            Objects.requireNonNull(answer);
            return validTicketConditionByAnswer(conditionMap, answer.getInnerMap(), RespondentStatusEnum.FINISH.getIndex());
        } catch (Exception e) {
            log.error("[Ticket] 检查工单条件出错。答卷序号：{}, 工单触发条件{}, 问卷答案：{}", seq, condition, respondentBySeq.getAnswers(), e);
        }
        return false;
    }

    /**
     * 通过答案校验工单条件
     *
     * @param ticketCondition 工单条件
     * @param answer          答卷答案
     * @param rspdStatus      答卷状态
     * @return boolean  校验结果
     * @author jy.zhao
     * @date 2021/9/2 21:12
     **/
    public static boolean validTicketConditionByAnswer(Object ticketCondition, Map<String, Object> answer, Integer rspdStatus) {
        // 解析嵌套条件。
        if (ticketCondition instanceof Map) {
            Map<String, Object> conditionMap = SurveyAnswerValidUtil.toMap(ticketCondition);
            // 工单规则不为空. rule 是为了兼容联系人打标签的条件
            if (Validator.isNotNull(conditionMap.get(Constants.LOGIC)) || Validator.isNotNull(conditionMap.get("rule"))) {
                //TicketRuleCondition.Condition condition = BeanUtil.mapToBean(conditionMap, TicketRuleCondition.Condition.class, true);
                TicketRuleCondition.Condition condition = BeanUtil.toBean(conditionMap, TicketRuleCondition.Condition.class);
                // logic==0 全部条件，1 任一条件
                int logic = 0;
                if (Validator.isNull(condition.getLogic()) && !"$and".equals(condition.getRule())) {
                    logic = 1;
                }
                List<Boolean> res = new ArrayList<>();
                // 获取条件中 过滤
                List<JSONObject> filters = CollUtil.isNotEmpty(condition.getFilters()) ? condition.getFilters() : new ArrayList<>();
                for (JSONObject filter : filters) {
                    // 把filter转换为Map。进行传递
                    Map<String, Object> filterMap = filter.getInnerMap();
                    boolean valid = validTicketConditionByAnswer(filterMap, answer, rspdStatus);
                    if (logic == Constants.TICKET_RULE_ALL_MATCH && !valid) {
                        return false;
                    } else if (logic == Constants.TICKET_RULE_ONE_MATCH && valid) {
                        return true;
                    }
                    res.add(valid);
                }
                // 找到为true的结果
                long count = res.stream().filter(item -> item).count();
                // 全部条件都要满足。
                if (logic == Constants.TICKET_RULE_ALL_MATCH) {
                    return count == res.size();
                } else {
                    // 任一条件，为true的数量大于0
                    return count > 0;
                }
            } else {
                // 检查预警条件
                FilterDTO filter = new FilterDTO();
                try {
                    //filter = BeanUtil.mapToBean(conditionMap, FilterDTO.class, true);
                    filter = BeanUtil.toBean(conditionMap, FilterDTO.class);
                    // 使用BeanUtil.mapToBean 转换后 JSON解析不了sourceQ，所以下面手动赋值
                    filter.setSourceQ(JSON.toJSONString(conditionMap.getOrDefault("sourceQ", Constants.BLANK)));
                    filter.setValue(JSON.toJSONString(conditionMap.getOrDefault("value", Constants.BLANK)));
                    // 根据答卷答案去检查工单预警条件
                    Map<String, Object> checkResult = SurveyAnswerValidUtil.validTicketCondition(filter, answer, rspdStatus);
                    return CollUtil.isNotEmpty(checkResult);
                } catch (Exception e) {
                    log.error("条件检查错误 条件:{}, 答案：{}", filter, answer, e);
                    return false;
                }
            }

        } else if (SurveyAnswerValidUtil.isInstance(ticketCondition, DataTypeEnum.LIST)) {
            //  如果入参condition是 list 则满足任一条件即返回 True
            for (Object condition : SurveyAnswerValidUtil.toList(ticketCondition)) {
                if (validTicketConditionByAnswer(condition, answer, rspdStatus)) {
                    return true;
                }
            }
            return false;
        } else {
            return false;
        }
    }

    /**
     * 转换数据为Record.Data
     *
     * @param checkResultData 检查工单后返回的数据
     * @param ticketConfigId  工单配置id
     * @return Data
     * @author jy.zhao
     * @date 2021/8/20 17:17
     **/
    public static Map<String, List<Object>> dealCheckTicketData(Object checkResultData, String ticketConfigId) {
        Map<String, List<Object>> result = new HashMap<>(Constants.DEFAULT_MAP_INITIAL_CAPACITY);
        if (SurveyAnswerValidUtil.isInstance(checkResultData, DataTypeEnum.LIST)) {
            for (Object answer : SurveyAnswerValidUtil.toList(checkResultData)) {
                if (!SurveyAnswerValidUtil.isInstance(answer, DataTypeEnum.MAP)) {
                    continue;
                }
                SurveyAnswerValidUtil.toMap(answer).forEach((key, val) -> {
                    Map<String, Object> valMap = null;
                    if (val instanceof TitleHandleResultDTO) {
                        valMap = BeanUtil.beanToMap(val);
                    }
                    if (SurveyAnswerValidUtil.isInstance(val, DataTypeEnum.MAP)) {
                        valMap = SurveyAnswerValidUtil.toMap(val);
                    }
                    if (!Objects.isNull(valMap)) {
                        valMap.put("ruleID", ticketConfigId);
                        List<Object> list = result.getOrDefault(key, new ArrayList<>());
                        list.add(valMap);
                        result.put(key, list);
                    }
                });
            }
        }
        return result;
    }

    /**
     * 解析工单条件
     *
     * @param ticketCondition 工单条件
     * @param answer          答卷数据 key为题目编号，value为答案
     * @param rspdStatus      答卷状态，默认为成功完成'
     * @return List<Object> 结果
     * @author jy.zhao
     * @date 2021/8/18 11:31
     **/
    public static List<Object> parseTicketCondition(Object ticketCondition, Map<String, Object> answer, Integer rspdStatus) {
        // 解析嵌套条件。
        if (ticketCondition instanceof Map) {
            Map<String, Object> conditionMap = SurveyAnswerValidUtil.toMap(ticketCondition);
            // 工单规则不为空
            if (Validator.isNotNull(conditionMap.get(Constants.LOGIC))) {
                // 如果conditionMap中存在logic，就说明是第一次传递，可以转换为TicketRuleCondition.Condition
                //TicketRuleCondition.Condition condition = BeanUtil.mapToBean(conditionMap, TicketRuleCondition.Condition.class, true);
                TicketRuleCondition.Condition condition = BeanUtil.toBean(conditionMap, TicketRuleCondition.Condition.class);
                // logic==0 全部条件，1 任一条件
                int logic = condition.getLogic();
                // 获取条件中 过滤
                List<JSONObject> filters = CollUtil.isNotEmpty(condition.getFilters()) ? condition.getFilters() : new ArrayList<>();
                List<Boolean> res = new ArrayList<>();
                List<Object> gidLs = new ArrayList<>();
                List<String> conditionNames = new ArrayList<>();
                for (JSONObject filter : filters) {
                    // 把filter转换为Map。进行传递
                    Map<String, Object> filterMap = filter.getInnerMap();
                    List<Object> result = parseTicketCondition(filterMap, answer, rspdStatus);
                    Object tmp = result.get(0);
                    Object sonGids = result.get(1);
                    res.add(toBool(tmp));
                    if (toBool(tmp)) {
                        conditionNames.addAll((List<String>) result.get(2));
                    }
                    if (toBool(tmp) && !(tmp instanceof Boolean) && !(tmp instanceof List)) {
                        gidLs.add(tmp);
                    } else if (toBool(tmp) && tmp instanceof Boolean && toBool(sonGids) && sonGids instanceof List) {
                        gidLs.addAll(SurveyAnswerValidUtil.toList(sonGids));
                    }
                }
                // 找到为true的结果
                long count = res.stream().filter(item -> item).count();
                // 全部条件都要满足。或者任一条件，为true的数量大于0
                if ((logic == Constants.TICKET_RULE_ALL_MATCH && count == res.size()) || logic == Constants.TICKET_RULE_ONE_MATCH && count > 0) {
                    if (StrUtil.isNotEmpty(condition.getTriggerName())) {
                        conditionNames.clear();
                        conditionNames.add(condition.getTriggerName());
                    }
                    return Arrays.asList(true, gidLs, conditionNames);
                }
                return Arrays.asList(false, new ArrayList<>(), new ArrayList<String>());
            } else {
                // 检查预警条件
                FilterDTO filter = new FilterDTO();
                List<String> conditionNames = new ArrayList<>();
                try {
                    //filter = BeanUtil.mapToBean(conditionMap, FilterDTO.class, true);
                    filter = BeanUtil.toBean(conditionMap, FilterDTO.class);
                    // 使用BeanUtil.mapToBean 转换后 JSON解析不了sourceQ，所以下面手动赋值
                    filter.setSourceQ(JSON.toJSONString(conditionMap.getOrDefault("sourceQ", Constants.BLANK)));
                    filter.setValue(JSON.toJSONString(conditionMap.getOrDefault("value", Constants.BLANK)));
                    if (StrUtil.isNotEmpty(filter.getTriggerName())) {
                        conditionNames.add(filter.getTriggerName());
                    }
                    // 根据答卷答案去检查工单预警条件
                    Map<String, Object> checkResult = SurveyAnswerValidUtil.validTicketCondition(filter, answer, rspdStatus);
                    return Arrays.asList(checkResult, new ArrayList<>(), conditionNames);
                } catch (Exception e) {
                    log.error("条件检查错误 条件:{}, 答案：{}", filter, answer, e);
                    return Arrays.asList(false, new ArrayList<>(), new ArrayList<String>());
                }
            }

        } else if (SurveyAnswerValidUtil.isInstance(ticketCondition, DataTypeEnum.LIST)) {
            //  如果入参condition是 list 则满足任一条件即返回 True
            for (Object condition : SurveyAnswerValidUtil.toList(ticketCondition)) {
                return parseTicketCondition(condition, answer, rspdStatus);
            }
            return Arrays.asList(new HashMap<>(Constants.DEFAULT_MAP_INITIAL_CAPACITY), new ArrayList<>(), new ArrayList<String>());
        } else {
            return Arrays.asList(new HashMap<>(Constants.DEFAULT_MAP_INITIAL_CAPACITY), new ArrayList<>(), new ArrayList<String>());
        }
    }

    /**
     * 模仿python的bool()
     *
     * @param o 对象
     * @return Boolean
     * @author jy.zhao
     * @date 2021/8/23 11:07
     **/
    public static boolean toBool(Object o) {
        if (Validator.isNull(o)) {
            return false;
        }
        if (o instanceof Map) {
            return MapUtil.isNotEmpty(SurveyAnswerValidUtil.toMap(o));
        }
        if (o instanceof Boolean) {
            return (boolean) o;
        }
        return !"0".equals(o.toString());
    }

    /**
     * 获取groupId和name
     *
     * @param orgId     组织id
     * @param groupCode groupcode
     * @param groupList groupList
     * @return Map<String, String> 返回groupId、groupName的map
     * @author jy.zhao
     * @date 2021/9/2 14:19
     **/
    private Map<String, String> getGroupIdName(String orgId, String groupCode, List<String> groupList) {
        Map<String, String> groupInfo = new HashMap<>(Constants.DEFAULT_MAP_INITIAL_CAPACITY);
        // 创建工单使用
        String groupId = "";
        String groupName = "";
        // 发送mq使用
        String userGroupCode = "";
        if (Validator.isNotEmpty(groupCode)) {
            List<GroupDTO> groupDTOS = ticketBaseUserGrpcService.listGroupByOrgIdAndCode(orgId, groupCode);
            if (Validator.isNull(groupDTOS)) {
                return groupInfo;
            }
            HashSet<String> groupIdSet = new HashSet<>(groupList);
            if (groupDTOS != null) {
                for (GroupDTO groupDTO : groupDTOS) {
                    String rootGroupId = CollUtil.isNotEmpty(groupDTO.getAncestors()) ? groupDTO.getAncestors().get(groupDTO.getAncestors().size() - 1) : groupDTO.getId();
                    // 暂时不限制groupcode只能是project所在组的子组
                    if (Validator.isEmpty(groupId) || groupIdSet.contains(rootGroupId)) {
                        groupId = groupDTO.getId();
                        groupName = groupDTO.getTitle();
                    }
                }
            }
        } else {
            GroupDTO rootGroup = ticketUserGrpcService.getRootGroupByOrgId(orgId);
            if (rootGroup != null) {
                groupId = rootGroup.getId();
                groupName = rootGroup.getTitle();
            }
        }
        // 获取用户组code。发送工单mq使用。
        if (Validator.isNotEmpty(groupId)) {
            GroupDTO groupDTO = ticketBaseUserGrpcService.getGroup(groupId);
            if (groupDTO != null) {
                userGroupCode = groupDTO.getCode();
            }
        }
        groupInfo.put("groupId", groupId);
        groupInfo.put("groupName", groupName);
        groupInfo.put("userGroupCode", userGroupCode);

        return groupInfo;
    }
}
